// en_crypt.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>

#include "clipboard.hpp"
#ifdef WIN32
#include <config.hpp>
#else
#include "../itoken/config.hpp"
#endif

#include <vector>
#include <sstream>


struct args
{
	enum task
	{
	   NULL_OP,
	   READ,
	   WRITE,
	   STORE_TOKEN,
	   WRITE_SINGLE_FILE	   
	} op;

	enum on_clipboard_task
	{
		NULL_CLIPBOARD_OP,
		RESET_CLIPBOARD
	} clipboard_op;

	void parse(int argc, char* const argv[]);

	bool multiple_pages;
	std::string output_filename;
	std::string config_filename;
	std::string token;

std::vector<unsigned short> indices;

};

void args::parse(int argc, char* const argv[])
{
	op = NULL_OP; 
	clipboard_op = NULL_CLIPBOARD_OP;
	multiple_pages =false;

	for(unsigned short j =1; j < argc; j++)
	{
		switch(argv[j][0])
		{
	   	case '-':
	   	case '/':
			switch(argv[j][1])
			{
			case 'r': case 'C':
          op = READ;
          for(unsigned short k=j; ((k < argc-1) 
						&& 	(argv[k+1][0] != '-') && (argv[k+1][0] != '/')); j=k, k++)
						{						
							std::istringstream num_as_stream(argv[k+1]); // list of blank separated numbers
							unsigned short idx(0);
							num_as_stream >> idx;
							if(num_as_stream.rdbuf()->in_avail() == 0 && idx >0)
							{
								indices.push_back(--idx);
								std::cout << "num = " << idx << std::endl;
							}
							else
								throw ("Expected a blank separated list of strictly positive indices");
						}
					break;
				case 'w':
					op = WRITE;
					break;
				case 'T':
					op = STORE_TOKEN;
					if(j < argc-1)
						token = argv[j+1];
					break;		
				case 'o':
					op = WRITE_SINGLE_FILE;
					if(j < argc -1 )
						output_filename = argv[j+1];
					break;
				case 'm': 
					multiple_pages = true;
					break;
				case 'c':
					if(j < argc -1)
						config_filename = argv[j+1];
					break;
				case 'Z': 
						clipboard_op = RESET_CLIPBOARD;
					break;
			}
			break;
		default: 				
			break;
		}	   
	}	

}

int main (int argc, char * const argv[]) {
    // insert code here...
	
	clipboard::reset();	
	struct args cmd_line;
	cmd_line.parse(argc, argv);

	try
	{	   	
		if(cmd_line.clipboard_op == args::RESET_CLIPBOARD) 
			throw args::RESET_CLIPBOARD;

		if(cmd_line.op == args::NULL_OP) 
			throw args::NULL_OP;
		
		if(cmd_line.config_filename.empty())
		{
    		throw ("missing configuration filename -c config_filename");
        }
		
		libtoken tk_interface(cmd_line.config_filename.c_str());
		itoken * token = tk_interface.getToken();
		//config c = token->get_config();
		//std::cout << (*token) << std::endl;

	switch(cmd_line.op)
	{
	 case args::WRITE:
		token->write(); break;
	 case args::STORE_TOKEN:
		token->write(cmd_line.token.c_str());
		break;	
	  case args::READ:
		//std::cout << "read token = " << token->read() << std::endl;
      if(!cmd_line.indices.empty())
			  clipboard::read_from(token, cmd_line.indices);
		  else
			  clipboard::read_from(token);

		break;	
  	  case args::WRITE_SINGLE_FILE:
		if(!cmd_line.output_filename.empty())
		{
			token->write(cmd_line.output_filename.c_str(), cmd_line.multiple_pages);		
		}
	  default: break;
	}
	

	}
	catch(const char* exc)
	{
		std::cout << exc << std::endl;
	}
	catch(args::task)
	{
		 	std::cout << "Operation not specified.\n\n";
		std::cout << "Possible usage: \n";
		std::cout << " -c <config_file_name>, configuration file for encoding ops, path included;" << std::endl;
		std::cout << " -w to automatically generate and encode a new token;" << std::endl;
		std::cout << " -r [num1 num2 numk], to read an encoded token or just an index set;" << std::endl;
		std::cout << " -T <token_string>,  to encode token_string" << std::endl;
		std::cout << " -o <output_filename>, to decode and write token to output_filename" << std::endl;
		std::cout << " -m to split token one character per page in the output file\n";

	}
	catch(args::on_clipboard_task) // just resetting clipboard
	{}

    return 0;
}
